using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace GoogleCalendarReminder.gui
{
    /// <summary>
    /// A form which displays a collection of GoogleCalendarReminder.EventEntityWrappers.
    /// </summary>
    public partial class AlertForm : Form
    {
        #region Private Data Members

        private EventServiceSubscriber _subscriber;
        private ContextMenuStrip _snoozeMenu;
        private System.Timers.Timer _snoozeTimer;
        private Size _defaultFormSize;
        private Point _defaultFormLocation;
        private bool _playSoundOnShown = true;

        private readonly string _moreInfoText = "More info...";

        #endregion

        #region Private Functions

        /// <summary>
        /// Displays the form when the snooze timer has elapsed.
        /// </summary>
        private void _snoozeTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new System.Timers.ElapsedEventHandler(_snoozeTimer_Elapsed), sender, e);
            }
            else
            {
                Show();
            }
        }

        /// <summary>
        /// Removes the selected item and closes the form if necessary.
        /// </summary>
        private void btnDismiss_Click(object sender, EventArgs e)
        {
            if (lstMain.SelectedItem != null && _subscriber != null)
            {
                int selectedIndex = lstMain.SelectedIndex;

                _subscriber.Events.Remove(lstMain.SelectedItem);
                lstMain_SelectedIndexChanged(this, EventArgs.Empty);

                try
                {
                    lstMain.SelectedIndex = selectedIndex;
                }
                catch (System.ArgumentOutOfRangeException)
                {
                    lstMain.SelectedIndex = --selectedIndex;
                }

                if (_subscriber.Events.Count == 0)
                {
                    Hide();
                }
            }
        }

        /// <summary>
        /// Shows the snooze menu.
        /// </summary>
        private void btnSnooze_Click(object sender, EventArgs e)
        {
            _snoozeMenu.Show(btnSnooze, btnSnooze.ClientRectangle.Left, btnSnooze.ClientRectangle.Bottom);
        }

        /// <summary>
        /// Shows the form if events exist.
        /// </summary>
        private void Events_ListChanged(object sender, EventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new EventHandler(Events_ListChanged), sender, e);
            }
            else
            {
                if (_subscriber.Events.Count > 0)
                {
                    Show();
                    TopMost = true;
                    TopMost = false;
                }
            }
        }

        /// <summary>
        /// Attempts to open an items uri.
        /// </summary>
        private void lblMoreInformation_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            try
            {
                System.Diagnostics.Process.Start(e.Link.LinkData.ToString());
            }
            catch (Exception) { }
        }

        /// <summary>
        /// Attempts to open an items uri.
        /// </summary>
        private void lstMain_DoubleClick(object sender, EventArgs e)
        {
            if (lstMain.SelectedItem != null)
            {
                try
                {
                    System.Diagnostics.Process.Start(lstMain.SelectedItem.Uri);
                }
                catch (Exception) { }
            }
        }

        /// <summary>
        /// Updates the footer text when the selected item changes.
        /// </summary>
        private void lstMain_SelectedIndexChanged(object sender, EventArgs e)
        {
            lblFooter.Visible = false;
            lblFooter.Text = string.Empty;

            if (lstMain.SelectedItem != null)
            {
                EventEntryWrapper selectedEvent = lstMain.SelectedItem;

                lblFooter.Text =
                    selectedEvent.Description +
                    (selectedEvent.Description == string.Empty ? string.Empty : " ") +
                    _moreInfoText;

                lblFooter.Links.Clear();
                lblFooter.Links.Add(lblFooter.Text.Length - _moreInfoText.Length, _moreInfoText.Length, selectedEvent.Uri);
                lblFooter.Visible = true;
            }
        }

        /// <summary>
        /// Selects the first item in the list.
        /// </summary>
        private void selectFirstListItem()
        {
            if (lstMain.Items.Count > 0)
            {
                lstMain.SelectedIndex = 0;
            }
        }

        #region Snooze Functions

        /// <summary>
        /// Hides the form and configures the snooze timer.
        /// </summary>
        /// <param name="seconds">The seconds to snooze.</param>
        private void startSnooze(int seconds)
        {
            Hide();
            _snoozeTimer.Stop();
            _snoozeTimer.Interval = seconds * 1000;
            _snoozeTimer.Start();
        }

        private void snooze5min_Click(object sender, EventArgs e)
        {
            startSnooze(5 * 60);
        }

        private void snooze15min_Click(object sender, EventArgs e)
        {
            startSnooze(15 * 60);
        }

        private void snooze30min_Click(object sender, EventArgs e)
        {
            startSnooze(30 * 60);
        }

        private void snooze1hr_Click(object sender, EventArgs e)
        {
            startSnooze(1 * 60 * 60);
        }

        private void snooze2hr_Click(object sender, EventArgs e)
        {
            startSnooze(2 * 60 * 60);
        }

        #endregion

        #endregion

        #region Protected Functions

        /// <summary>
        /// Hides the form instead of closing it.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);

            if (e.CloseReason == CloseReason.UserClosing)
            {
                e.Cancel = true;
                Hide();
            }
        }

        /// <summary>
        /// Configures the form for displaying.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (Visible)
            {
                Size = _defaultFormSize;
                Location = _defaultFormLocation;

                selectFirstListItem();

                if (PlaySoundOnShown)
                {
                    System.Media.SystemSounds.Asterisk.Play();
                }
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of the GoogleCalendarReminder.gui.AlertForm class.
        /// </summary>
        public AlertForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Creates a new instance of the GoogleCalendarReminder.gui.AlertForm class.
        /// </summary>
        /// <param name="subscriber">The subscriber.</param>
        /// <exception cref="System.ArgumentNullException">Parameter can't be null.</exception>
        public AlertForm(EventServiceSubscriber subscriber)
            : this()
        {
            if (subscriber == null)
                throw new ArgumentNullException("Parameter can't be null.");

            _defaultFormSize = Size;
            _defaultFormLocation = PointToScreen(Location);

            lstMain.SelectedIndexChanged += new EventHandler(lstMain_SelectedIndexChanged);
            lstMain.DoubleClick += new EventHandler(lstMain_DoubleClick);

            lblFooter.Text = string.Empty;
            lblFooter.Visible = false;
            lblFooter.LinkClicked += new LinkLabelLinkClickedEventHandler(lblMoreInformation_LinkClicked);

            _snoozeMenu = new ContextMenuStrip();
            
            ToolStripItem snooze5min = _snoozeMenu.Items.Add("For 5 minutes");
            ToolStripItem snooze15min = _snoozeMenu.Items.Add("For 15 minutes");
            ToolStripItem snooze30min = _snoozeMenu.Items.Add("For 30 minutes");
            ToolStripItem snooze1hr = _snoozeMenu.Items.Add("For 1 hour");
            ToolStripItem snooze2hr = _snoozeMenu.Items.Add("For 2 hours");

            _snoozeMenu.Items.AddRange(
                new ToolStripItem[] {
                    snooze5min,
                    snooze15min,
                    snooze30min,
                    snooze1hr,
                    snooze2hr });

            snooze5min.Click += new EventHandler(snooze5min_Click);
            snooze15min.Click += new EventHandler(snooze15min_Click);
            snooze30min.Click += new EventHandler(snooze30min_Click);
            snooze1hr.Click += new EventHandler(snooze1hr_Click);
            snooze2hr.Click += new EventHandler(snooze2hr_Click);

            _snoozeTimer = new System.Timers.Timer();
            _snoozeTimer.AutoReset = false;
            _snoozeTimer.Elapsed += new System.Timers.ElapsedEventHandler(_snoozeTimer_Elapsed);

            Subscriber = subscriber;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets the value that determines whether or not a sound is played when the form is shown.
        /// </summary>
        public bool PlaySoundOnShown
        {
            get { return _playSoundOnShown; }
            set { _playSoundOnShown = value; }
        }

        /// <summary>
        /// Gets or sets the subscriber.
        /// </summary>
        public EventServiceSubscriber Subscriber
        {
            get { return _subscriber; }
            set
            {
                if (Subscriber != null)
                {
                    Subscriber.Events.ListChanged -= new EventHandler(Events_ListChanged);
                }

                _subscriber = value;
                lstMain.DataSource = Subscriber.Events;

                if (Subscriber != null)
                {
                    Subscriber.Events.ListChanged += new EventHandler(Events_ListChanged);
                }
            }
        }

        #endregion
    }
}